home *** CD-ROM | disk | FTP | other *** search
- * Program periodicities
- *
- * This program was typed directly from the book:
- *
- * FOURIER ANALYSIS OF TIME SERIES: AN INTRODUCTION
- * by Peter Bloomfield
- * John Wiley & Sons, 1976
- *
- * This main program and subroutine datin are used to
- * input data for, and output results from, fitting a
- * model of hidden periodicities to a time series.
- * The time series data is read by datin . Data input
- * from a control file are conv , lim , and appflg (which
- * are defined in subroutine optom ), the number of
- * frequencies to be fitted, followed by the list of
- * approximate frequencies and the estimated sine and
- * cosine coefficients.
- *
- * Note:- An approximate fit is obtained if appflg and lim
- * are set to unity and conv is set to pi or similar
- * large number. An 'exact' fit is obtained with
- * appflg set to zero, lim to 5 (for example) and
- * conv set to a small number like 1.0e-05 to allow
- * the algorithm to iterate to convergence.
- *
- *
- real x(600),y(600),fre(10),a(10),b(10)
- integer appflg
- character fname1,fname2,fname3
- *
- write(6,1)
- 1 format("1Enter the time series file name")
- read,fname1
- print,"Enter the control parameter filename"
- read,fname2
- print,"Enter the output file name"
- read,fname3
- *
- call datin (x,n,start,step,1,fname1)
- open(unit=2,file=fname2)
- read(2) conv,lim,appflg
- open(unit=3,file=fname3)
- write(3,4) conv,lim,appflg
- 4 format(" For this run, conv =",e12.4/
- & " lim =",i5/
- & " appflg =",i5)
- read(2) m
- read(2) (fre(j),a(j),b(j),j=1,m)
- write(3,5)
- 5 format(/" Initial values are -")
- write(3,3) (j,fre(j),a(j),b(j),j=1,m)
- 3 format(" Component Frequency Cosine Sine"/
- & " Coefficients"/
- & (i5,f15.7,2e15.6))
- *
- call optom (x,n,rmu,fre,a,b,m,conv,lim,appflg,y)
- *
- write(3,6)
- 6 format(/" Final values are -")
- write(3,3) (im,fre(im),a(im),b(im),im=1,m)
- ss = 0.0
- do 30 i = 1 , n
- temp = x(i) - rmu
- do 40 j = 1 , m
- arg = float(i-1) * fre(j)
- temp = temp - a(j) * cos(arg) - b(j) * sin(arg)
- 40 continue
- ss = ss + temp**2
- 30 continue
- write(3,7) rmu,ss
- 7 format(/" Fitted constant is ",e15.6/
- & " Residual Sum of Squares is",e15.6)
- stop
- end
-
-
- subroutine datin ( x , n , start , step , m , fname)
- *
- * This subroutine is used to input a series of values
- * (in run time format) and some associated quantities
- * (in fixed format). The first four data records are -
- *
- * 1 A header record (72 bytes)
- * 2 Value of n (i5)
- * 3 The data format (72 bytes)
- * 4 Start and step (2f10.5)
- *
- * Parameters are -
- *
- * Name Type Value
- * On Entry On Return
- *
- * x Real array Not used The series
- *
- * n Integer Not used Series length
- *
- * start Real Not used Time value at the
- * first data point
- *
- * step Real Not used Time increment
- * between data points
- *
- * m Integer Logical unit number Unchanged
- *
- * fname Character input file name Unchanged
- *
- real x(512)
- character head , form , fname
- open(unit=m,file=fname,access="sequential",recl=80)
- read(m,1) head,n,form,start,step
- 1 format(a72/i5/a72/2f10.5)
- write(6,2) head,n,form,start,step
- 2 format("0The data header reads -"/1x,a72/
- & " The series length is",i6/
- & " The data format is -"/1x,a72/
- & " time origin is",f11.5,
- & ", time increment is",f11.5)
- read(m,form) (x(i),i=1,n)
- close(unit=m)
- return
- end
-
-
- subroutine optom (x,n,rmu,fre,a,b,m,conv,lim,appflg,y)
- *
- * This subroutine, with subprograms localm , ssreg ,
- * stats and parms , implements the algorithm for
- * the least-squares fitting of the model of hidden
- * periodicities. Parameters are:-
- *
- * Name Type Value
- * On Entry On Return
- *
- * x Real array The time series Unchanged
- *
- * n Integer Series length Unchanged
- *
- * rmu Real Not used Constant term
- *
- * fre Real array Starting values for Final values
- * the frequencies to
- * be fitted
- *
- * a Real array Starting values for Final values
- * cosine coefficients
- *
- * b Real array Starting values for Final values
- * sine coefficients
- *
- * m Integer Number of components Unchangd
- * to be fitted
- *
- * conv Real Convergence criterion Unchanged
- * Iteration ceases when
- * in one cycle, no
- * frequency changes by
- * more than conv
- *
- * lim Integer Maximum number of Unchanged
- * cycles of iteration
- *
- * appflg Integer Flag controlling Unchanged
- * whether approximate
- * ( 1 ) or exact ( 0 )
- * least squares is to
- * be usd
- *
- * Notes.
- * 1. If values of n or m exceeding 600 and 10.
- * respectively, are used, the dimension statement
- * below should be changed accordingly.
- * 2. Use of exact least squares (appflg = 0) will
- * cause longer execution times.
- * 3. The frequencies in general converge to values
- * within 2*pi/n of their starting values. The
- * starting values should be given to at least this
- * accuracy, or the algorithm may be trapped by
- * side-lobes. Starting values of the cosine and
- * sine coefficients are less critical, and may be
- * set to zero.
- *
- real localm
- real x(n) , y(n) , fre(10) , a(10) , b(10)
- integer appflg
- *
- * *** root of relative machine epsilon
- *
- eps = 1.0
- 1 eps = 0.5 * eps
- epsp1 = eps + 1.0
- if (epsp1 .gt. 1.0) go to 1
- eps = sqrt(eps)
- *
- pi = 4.0 * atan(1.0)
- t = conv
- delta = pi / float(n)
- do 10 kount = 1 , lim
- sum = 0.0
- do 20 i = 1 , n
- y(i) = x(i)
- do 30 j = 1 , m
- arg = float(i-1)* fre(j)
- 30 y(i) = y(i) - a(j) * cos(arg) - b(j) * sin(arg)
- 20 sum = sum + y(i)
- rmu = sum / float(n)
- test = 0.0
- do 40 j = 1 , m
- do 60 i = 1 , n
- y(i) = x(i) - rmu
- do 50 k = 1 , m
- if (k .eq. j) go to 50
- arg = float(i-1) * fre(k)
- y(i) = y(i) -a(k) * cos(arg) - b(k) * sin(arg)
- 50 continue
- 60 continue
- dummy = localm (fre(j) - delta , fre(j) + delta,
- & eps , t , temp , y , n , appflg)
- test = amax1 (test , abs(fre(j)-temp))
- fre(j) = temp
- 40 call parms (y , n , fre(j) , appflg , a(j) , b(j))
- if (test .lt. conv) return
- delta = test + 2.0 * t
- 10 continue
- return
- end
-
-
- real function localm (a , b , eps , t , x , y , n , appflg)
- *
- * This is the FORTRAN function LOCALM given by
- * Richard Brent in
- * Algorithms for minimization without derivatives
- * (Prentice-Hall, 1973).
- * It finds a local minimum of the function f in the
- * interfal (a , b).
- * t and eps define a tolerance tol = eps * abs(x) + t ,
- * where x is the current approximation to the position
- * of the minimum. The minimum is found with an error
- * of at most 3 * tol.
- * f is not evaluated at points closer than tol.
- * a suitable value for eps is the square root of the
- * relative machine precision. For more detail see the
- * above reference.
- *
- real m , y(n)
- integer appflg
- sa = a
- sb = b
- x = sa + 0.381966 * (sb - sa)
- w = x
- v = w
- e = 0.0
- * fx = f(x)
- fx = -ssreg (y , n , x , appflg)
- fw = fx
- fv = fw
- 10 m = 0.5 * (sa + sb)
- tol = eps * abs(x) + t
- t2 = 2.0 * tol
- if (abs(x-m) .le. t2-0.5*(sb-sa)) go to 190
- r = 0.0
- q = r
- p = q
- if (abs(e) .le. tol) go to 40
- r = (x - w) * (fx - fv)
- q = (x - v) * (fx - fw)
- p = (x - v) * q - (x - w) * r
- q = 2.0 * (q - r)
- if (q .le. 0.0) go to 20
- p = -p
- go to 30
- 20 q = -q
- 30 r = e
- e = d
- 40 if (abs(p) .ge. abs(0.5*q*r)) go to 60
- if ((p .le. q*(sa-x)) .or. (p .ge. q*(sb-x))) go to 60
- d = p / q
- u = x + d
- if ((u-sa .ge. t2) .and. (sb-u .ge. t2)) go to 90
- if (x .ge. m) go to 50
- d = tol
- go to 90
- 50 d = -tol
- go to 90
- 60 if (x .ge. m) go to 70
- e = sb - x
- go to 80
- 70 e = sa - x
- 80 d = 0.381966 * e
- 90 if (abs(d) .lt. tol) go to 100
- u = x + d
- go to 120
- 100 if (d .le. 0.0) go to 110
- u = x + tol
- go to 120
- 110 u = x - tol
- * 120 fu = f(u)
- 120 fu = -ssreg(y , n , u , appflg)
- if (fu .gt. fx) go to 150
- if (u .ge. x) go to 130
- sb = x
- go to 140
- 130 sa = x
- 140 v = w
- fv = fw
- w = x
- fw = fx
- x = u
- fx = fu
- go to 10
- 150 if (u .ge. x) go to 160
- sa = u
- go to 170
- 160 sb = u
- 170 if ((fu .gt. fw) .and. (w .ne. x)) go to 180
- v = w
- fv = fw
- w = u
- fw = fu
- go to 10
- 180 if ((fu .gt. fv) .and. (v .ne. x) .and. (v .ne. w)) go to 10
- v = u
- fv = fu
- go to 10
- 190 localm = fx
- return
- end
-
-
- function ssreg (y , n , omega , appflg)
- *
- * This function returns the sum of squares (approximate
- * or exact) associated with omega. Parameters are
- *
- * Name Type Value on Entry (none are changed)
- *
- * y Real array The time series
- *
- * n Integer Series length
- *
- * omega Real The frequency
- *
- * appflg Integer 1 for approximate least squares
- * 0 for exact least squares
- *
- real y(n)
- integer appflg
- call stats (y , n , omega , cy , sy)
- if (appflg .eq. 1) go to 10
- rn = n
- con = sin(rn*omega)/sin(omega)
- arg = (rn-1.0)*omega
- cc = 0.5*(rn+cos(arg)*con)
- cs = 0.5*sin(arg)*con
- ss = rn-cc
- ssreg = (ss*cy**2-2.0*cs*cy*sy+cc*sy**2)/(cc*ss-cs**2)
- return
- 10 continue
- ssreg = (cy**2+sy**2)*2.0/float(n)
- return
- end
-
-
- subroutine stats (y , n , omega , cy , sy)
- *
- * This subroutine returns the cosine and sine sums of a
- * time series. Parameters are
- *
- * Name Type Value
- * On Entry On Return
- *
- * y Real array The time series Unchanged
- *
- * n Integer Series length Unchanged
- *
- * omega Real The frequency Unchanged
- *
- * cy Real Not used Cosine sum
- *
- * sy Real Not used Sine sum
- *
- real y(n)
- cy = 0.0
- sy = 0.0
- do 10 i = 1 , n
- arg = float(i-1) * omega
- cy = cy + cos(arg) * y(i)
- sy = sy + sin(arg) * y(i)
- 10 continue
- return
- end
-
-
- subroutine parms (y , n , omega , appflg , a , b)
- *
- * This subroutine returns the (exact or approximate)
- * least squares estimate of the cosine and sine
- * coefficients of a single periodic component.
- * paramters are
- *
- * Name Type Value
- * On Entry On Return
- *
- * y Real array The time series Unchanged
- *
- * n Integer Series length Unchanged
- *
- * omega Real The frequency Unchanged
- *
- * appflg Integer 1 or 0 for Unchanged
- * approximate or
- * exact least squares,
- * respecively
- *
- * a Real Not used cos coefficient
- *
- * b Real Not used sin coefficient
- *
- real y(n)
- integer appflg
- call stats (y , n , omega , cy , sy)
- rn = float(n)
- if (sin(omega) .eq. 0.0) go to 20
- if (appflg .eq. 1) go to 10
- con = sin(rn*omega)/sin(omega)
- arg = (rn-1.0)*omega
- cc = 0.5*(rn+cos(arg)*con)
- cs = 0.5*sin(arg)*con
- ss = rn-cc
- del = cc*ss-cs**2
- a = (cy*ss-sy*cs)/del
- b = (sy*cc-cy*cs)/del
- return
- 10 continue
- a = 2.0*cy/rn
- b = 2.0*sy/rn
- return
- 20 a = cy/rn
- b = 0.0
- return
- end
-